[Day29] 記錄指針是海賊王世界裡一種外觀像手錶,中央為球形的特殊羅盤。可以偵測並記下偉大航路內各個島嶼放出的磁場,為海上航行的船隻提供正確的路線。
延續昨天的主題,我們已經知道單體方法是怎麼被定義的,但它既不屬於類別方法,也不是實體方法,那它到底被定義在哪裡呢?
先說結論:單體方法被寫在 Singleton Class
裡。
走過的路 是一陣魔術···
···都化作這目光 吟唱成一首歌
抱歉突然想唱個歌,讓我們進入正題~
Singleton Class
是什麼?如果是初學 Ruby 這門程式語言的朋友,一開始幾乎不太會接觸到 Singleton Class
的概念。在一般的繼承鍊裡,我們只學過 Class
< Object
< BaseObject
這種一直往上找,層層相疊的繼承關係。
不過實際上在 Ruby 的物件導向設計裡,還有一個非常神祕的類別,
那就是 Singleton Class
:
metaclass
或 eigenclass
Singleton Class
上定義的方法就是單體方法回顧昨天的例子:
class Cat
# ...
end
meme = Cat.new
def meme.feet
puts "有穿白襪"
end
meme.feet # => 有穿白襪
雖然單體方法 feet
是寫在類別的外面,但 Ruby 其實有偷偷為 meme
準備了一個 Singleton Class
,而 feet
方法就被定義在裡面:
class Cat
# ...
end
meme = Cat.new
# singleton class of meme
def meme.feet
puts "有穿白襪"
end
# end
meme.feet # => 有穿白襪
有看到
Singleton Class
嗎?沒看到?
嗯··· 代表你非常正常!
通常在開了天眼後才看得到
所以泰安老師叫它「跟鬼一樣的類別」!
Singleton Class
?其實我還不知道如何在 irb 裡顯示物件的 Singleton Class
,不過,通過類別物件的繼承或許可以看出一點端倪。
繼承最核心的概念就是子層類別的物件可以拿父層類別的方法來用,類別方法也同樣遵循著這套繼承的規則
class Animal
def self.all
puts "全部的動物"
end
end
class Cat < Animal
def self.all
puts "貓咪王國!"
end
end
Cat.all # => 貓咪王國!
如果有同名的類別方法,則會優先呼叫定義在 Singleton Class
的那個。
昨天有提到,類別方法其實也是單體方法的一種,所以每個類別的類別方法就會定義在自己的 Singleton Class
上,像是這樣:
現在我們知道了,當一個 Ruby 物件在呼叫方法時,會先往 Singlton Class
找看看,沒有的話,會再往上從繼承的類別裡尋找。
既然都已經講了 Singleton Class
,那就不得不來介紹 Ruby 裡的物件導向了!
「物件導向」這四個字看起來又是個高大上,一開始總覺得如果能說清楚這個概念,好像自己會變很聰明,但事實上,它就只是個語言的設計概念。(另一個事實則是我笨)
接下來會用到這兩個方法:
方法 | 說明 |
---|---|
superclass |
尋找自己繼承的父層類別 |
class |
尋找自己所屬的類別 |
superclass
和 class
能有助於更加釐清 Singleton Class
以及 Ruby 裡物件導向的概念。
繼續沿用剛才的例子,並用這兩個方法來看看吧!
class Cat
# ...
end
meme = Cat.new
meme.class # => Cat
meme.superclass # => NoMethodError (undefined method `superclass' for #<Cat:0x00007fd482123eb0>)
咦? superclass
噴錯了!不過沒關係,因為實體物件本來就沒有繼承的父層類別,繼續來看:
Cat.class # => Class
Cat.superclass # => Object
Cat
這個類別是屬於一個叫做 Class
的類別,或者說,在 Ruby 裡,所有的類別都屬於 Class
這個類別。
而 Cat
這個類別是繼承自一個叫做 Object
的類別,"Object",也就是物件的意思,以一個物件導向的語言來說,出現這個名字很合理,繼續看下去:
我們來對 Class
試試看吧:
Class.class # => Class
Class.superclass # => Module
這次出現了有趣的事情,果然全天下的類別都是屬於 Class
這個類別,因此 Class
所屬的類別也是 Class
自己。
而 Class
繼承的類別居然是 Module
! 這不是模組嗎?不過仔細一瞧才發現大寫的 Module
是類別,小寫的 module
則是模組,只是,Ruby 設計者沒想過會讓大家困惑嗎XDDD
做一個模組出來試試看:
module Flyable
end
Flyable.class # => Module
Flyable.superclass # => NoMethodError (undefined method `superclass' for Flyable:Module)
Flyable
這個模組屬於 Module
這個類別,而 Flyable
沒有向上的繼承類別(這是因為 Ruby 裡的模組本來就無法繼承)
但令人驚訝的是 Class
竟然是繼承自 Module
!當初在學習時,就有發現模組和類別兩個概念很像,但我原本一直以為模組可能是類別的副產品之類的,
沒想到···竟然是反過來
真是世事難料啊!!!
接著我們來看看這個 Object
Object.class # => Class
Object.superclass # => BasicObject
不出所料,Object
的類別是 Class
,而繼承自 BasicObject
類別這個又是什麼?名字怎麼都取這麼像啊!
BasicObject.class # => Class
BasicObject.superclass # => nil
BasicObject
的類別也是 Class
,而再往上就沒有了!
目前可以得到像這樣的圖:
最後來看 Module
:
Module.class # => Class
Module.superclass # => Object
嗯···類別是 Class
,然後繼承自···咦!Object
!那不就
Object.class # => Class
Class.superclass # => Module
Module.superclass # => Object
你們這樣繞來繞去,弄得我頭很痛啊!還好網路上已經有大大梳理好它們彼此之間的關係
看圖是不是清楚多了呢?
說實話,韓劇每個角色的關係圖都比這都複雜多了!
今天的文章就先到這裡了,
以上就是我對 Ruby 物件導向的理解,自己覺得這篇的脈絡有點亂,就和思緒一樣,可能也有一些理解錯誤的地方,大大們如果看到的話還請不吝指出,日後還會繼續進行釐清和整理的。
覺得好像感冒了...頭好昏啊!
參考來源
Metaprogramming in Ruby 2 - The Object Model
speedred - Ruby 的繼承鍊 (1) - 如何實踐物件導向